Introduction

Macau has undergone significant land reclamation over the last few decades. Due to urban growth and limited original land area, reclamation has played a dominant role in shaping the city’s modern landscape. This study utilizes Landsat imagery to visualize and quantify land expansion from 1990 to 2025, examining the temporal evolution of Macau’s land extent.

本研究運用 Landsat 影像呈現並分析澳門過去三十多年來的土地擴張。

Data

The macau_geojson was downloaded from the Map of Macau and GIS data — download OSM vector layers and used as the spatial boundary for cropping the Landsat imagery. This polygon boundary is used to crop each Landsat scene to the study area.

macau_polygon <- st_read("https://geo2day.com/asia/china/macau.geojson")
## Reading layer `macau' from data source 
##   `https://geo2day.com/asia/china/macau.geojson' using driver `GeoJSON'
## Simple feature collection with 1 feature and 1 field
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 113.524 ymin: 22.073 xmax: 113.634 ymax: 22.221
## Geodetic CRS:  WGS 84
plot(macau_polygon)

Landsat imagery from 1990-2025

The analysis uses multi-temporal Landsat imagery from 1990-2025, downloaded from the United States Geological Survey(USGS) EarthExplorer Platfrom. The Landsat data of each year contains multiple single band tif files. These bands must be stacked into a multi-band raster before visualization or analysis. For more detail information about Landsat spectral bands, refer to Spectral Bands and Applications - NASA Science.

Landsat4_19901224

Landsat4

landsat4_19901224 <- stack(
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B1.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B2.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B3.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B4.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B5.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_ST_B6.TIF",
 "LT04_L2SP_122045_19901224_20200915_02_T1/LT04_L2SP_122045_19901224_20200915_02_T1_SR_B7.TIF"

)

names(landsat4_19901224) <- c("blue", "green", "red", "NIR", "SWIR","Thermal", "Mid-Infrared-IR") #rename bands

# plotRGB(landsat4_19901224, r=3, g = 2, b = 1, stretch = "lin")

summary(landsat4_19901224)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.19% of all cells)
##             blue    green      red      NIR     SWIR  Thermal Mid.Infrared.IR
## Min.        7765     6810     7769     7631     7308    34005            6726
## 1st Qu.     9853     9894     9023     8358     7887    41497            7712
## Median     10290    10885    10167    10067     9370    42118            8670
## 3rd Qu.    11574    12136    12347    15820    15353    42355           12981
## Max.       65535    65535    65535    65535    65535    48143           43193
## NA's    15652119 15652119 15652119 15652119 15652119 16295241        15652119

Landsat5_1995

Landsat5

landsat5_19951230 <- stack(
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B1.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B2.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B3.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B4.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B5.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_ST_B6.TIF",
  "LT05_L2SP_122045_19951230_20200911_02_T1/LT05_L2SP_122045_19951230_20200911_02_T1_SR_B7.TIF"
)

names(landsat5_19951230) <- c("blue", "green", "red", "NIR", "SWIR", "Thermal", "Mid-Infrared") #rename bands

summary(landsat5_19951230)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.19% of all cells)
##             blue    green      red      NIR     SWIR  Thermal Mid.Infrared
## Min.        7298     7378     7323     7601     6851    20833         6775
## 1st Qu.     9396     9008     8356     8033     7455    41165         7360
## Median      9794     9519     8674     8180     7574    41898         7555
## 3rd Qu.    10144    10492     9704     9224     7852    42204         7760
## Max.       65535    32576    34031    36160    39083    48386        55567
## NA's    16170679 16170679 16170679 16170679 16170679 16839792     16170679
#crs(landsat5_19951230)

Landsat5_2000

Landsat5_20000906 <- stack(
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B1.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B2.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B3.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B4.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B5.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_ST_B6.TIF",
  "LT05_L2SP_122045_20000906_20200906_02_T1/LT05_L2SP_122045_20000906_20200906_02_T1_SR_B7.TIF"
)

names(Landsat5_20000906) <- c("blue", "green", "red", "NIR", "SWIR", "Thermal", "Mid-Infrared") #rename bands

summary(Landsat5_20000906)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.18% of all cells)
##             blue    green      red      NIR     SWIR  Thermal Mid.Infrared
## Min.        6553     7301     7071     5673     7101      293         7102
## 1st Qu.     9165     9288     8869     8669     8179    42224         8092
## Median     10009    10461     9769     9635     8756    44346         8504
## 3rd Qu.    12701    12956    12345    17967    14075    44960        10993
## Max.       65535    65535    65535    65535    65535    53920        33750
## NA's    16272093 16272093 16272093 16272093 16272093 16993723     16272093

Landsat5_2005

Landsat7 can not use

Landsat5_20051022 <- stack(
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B1.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B2.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B3.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B4.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B5.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_ST_B6.TIF",
  "LT05_L2SP_122045_20051022_20200901_02_T1/LT05_L2SP_122045_20051022_20200901_02_T1_SR_B7.TIF"
  )

names(Landsat5_20051022) <- c("blue", "green", "red", "NIR", "SWIR", "Thermal", "Mid-Infrared") #rename bands

summary(Landsat5_20051022)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.19% of all cells)
##             blue      green        red        NIR     SWIR  Thermal
## Min.          21     2766.0     4438.0     5986.0     6602      293
## 1st Qu.     9971     9731.0     8869.0     8371.0     7879    44359
## Median     10456    10462.0     9228.0     8633.0     8068    44445
## 3rd Qu.    10870    11229.5    10302.5    12128.5     9532    44596
## Max.       65535    65535.0    65535.0    65535.0    65535    53023
## NA's    15746497 15743798.0 15743798.0 15743798.0 15743798 16445022
##         Mid.Infrared
## Min.            7072
## 1st Qu.         7707
## Median          7965
## 3rd Qu.         8590
## Max.           34869
## NA's        15743798

Landsat5_2010

Landsat5_20100326 <- stack(
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B1.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B2.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B3.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B4.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B5.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_ST_B6.TIF",
  "LT05_L2SP_122045_20100326_20200824_02_T1/LT05_L2SP_122045_20100326_20200824_02_T1_SR_B7.TIF"
)

names(Landsat5_20100326) <- c("blue", "green", "red", "NIR", "SWIR", "Thermal", "Mid-Infrared") #rename bands

summary(Landsat5_20100326)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.18% of all cells)
##             blue    green      red      NIR     SWIR  Thermal Mid.Infrared
## Min.        4294     5635     6431     9438     8205      293         7726
## 1st Qu.    11465    11829    11233    12816    10840    38473         9447
## Median     15848    16399    16012    16787    16659    39337        15381
## 3rd Qu.    65535    25400    26028    26517    26035    42543        21860
## Max.       65535    36842    65535    65535    65535    51609        29990
## NA's    15828280 15828280 15828280 15828280 15828280 16529646     15828280

Landsat8_2015

Landsat8

Landsat8_20151018 <- stack(
 #"LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B1.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B2.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B3.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B4.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B5.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B6.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_SR_B7.TIF",
  "LC08_L2SP_122045_20151018_20200908_02_T1/LC08_L2SP_122045_20151018_20200908_02_T1_ST_B10.TIF"
)

names(Landsat8_20151018) <- c( "blue", "green", "red", "NIR", "SWIR", "SWIR2", 
                              "TIRS1") #rename bands

#Thermal Infrared Sensor (TIRS): Band 10 TIRS 1 (10.6 - 11.19 µm) 100 m
#"Coastal" = Band 1
summary(Landsat8_20151018)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.17% of all cells)
##             blue    green        red         NIR     SWIR    SWIR2    TIRS1
## Min.           8      501     1286.0     4396.00     7024     7224     1779
## 1st Qu.     7545     8046     7265.0     7196.00     7673     7651    42893
## Median      8033     8846     7679.5     7448.00     8123     8066    43954
## 3rd Qu.     8676     9872     9080.0    14610.25    11799     9555    44210
## Max.       51479    50344    51124.0    50987.00    38314    32640    51574
## NA's    17670117 17560794 17560794.0 17560794.00 17560794 17560794 18268483

Landsat8_2020

Landsat8_20201202 <- stack(
 #"LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B1.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B2.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B3.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B4.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B5.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B6.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_SR_B7.TIF",
  "LC08_L2SP_122045_20201202_20210312_02_T1/LC08_L2SP_122045_20201202_20210312_02_T1_ST_B10.TIF"
)


names(Landsat8_20201202) <- c( "blue", "green", "red", "NIR", "SWIR", "SWIR2", 
                              "TIRS1") #rename bands

#Thermal Infrared Sensor (TIRS): Band 10 TIRS 1 (10.6 - 11.19 µm) 100 m

summary(Landsat8_20201202)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.17% of all cells)
##             blue    green      red      NIR     SWIR    SWIR2    TIRS1
## Min.          19        3        1     2506     6872     7343    37954
## 1st Qu.     8002     8370     7301     7103     7529     7552    42471
## Median      8375     9058     7825     7254     7683     7684    42814
## 3rd Qu.     8872    10112     9413    13277    11250     9331    43142
## Max.       50082    49196    50005    50132    43358    42402    47476
## NA's    18474916 17866083 17720707 17564865 17564865 17564865 18274879

Landsat8_20250327

Landsat8_20250327 <- stack(
#"LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B1.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B2.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B3.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B4.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B5.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B6.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_SR_B7.TIF",
  "LC08_L2SP_122045_20250319_20250327_02_T1/LC08_L2SP_122045_20250319_20250327_02_T1_ST_B10.TIF"
)

names(Landsat8_20250327) <- c( "blue", "green", "red", "NIR", "SWIR", "SWIR2", 
                              "TIRS1") #rename bands


summary(Landsat8_20250327)
## Warning in .local(object, ...): summary is an estimate based on a sample of 1e+05 cells (0.17% of all cells)
##             blue    green      red        NIR     SWIR       SWIR2    TIRS1
## Min.           3     2296     2858     4790.0     7322     7422.00    37104
## 1st Qu.     7646     8135     7336     7233.0     7838     7825.00    41830
## Median      8084     8817     7553     7511.0     8060     8022.00    42440
## 3rd Qu.     8794     9902     9066    11305.5    10092     8905.25    42905
## Max.       30960    31221    32198    33644.0    35120    33106.00    48329
## NA's    17428941 17428941 17428941 17428941.0 17428941 17428941.00 18153114

Crop

This section use macau boundary polygon to crop the study area from each year Landsat stacked image.

macau_poly_utm <- st_transform(macau_polygon, crs = crs(Landsat5_20051022))
# match the projection
crop_1990 <- crop(landsat4_19901224, macau_poly_utm)
crop_1995 <- crop(landsat5_19951230, macau_poly_utm)
crop_2000 <- crop(Landsat5_20000906, macau_poly_utm)
crop_2005 <- crop(Landsat5_20051022, macau_poly_utm)
crop_2010 <- crop(Landsat5_20100326, macau_poly_utm)
crop_2015 <- crop(Landsat8_20151018, macau_poly_utm)
crop_2020 <- crop(Landsat8_20201202, macau_poly_utm)
crop_2025 <- crop(Landsat8_20250327, macau_poly_utm)

Visualization

True color composites were generated for each year using band combinations (e.g., R = Red, G = Green, B = Blue).

landsat_image_mo_list <- list(crop_1990, crop_1995, crop_2000, crop_2005, crop_2010,
                  crop_2015, crop_2020, crop_2025)


layer_date <- c("1990-12-24", "1995-12-30", "2000-09-06", "2005-12-17",
              "2010-10-28", "2015-10-18", "2020-12-02", "2025-03-27")


landsat_images_mo <- function(i){
  plotRGB(landsat_image_mo_list[[i]], r = 3, g = 2, b = 1, stretch = "lin")
  mtext(paste("Date:", layer_date[i], "\nCreated by: Jiatong Su"),
        side = 1, line = -1.5, adj = 0.5, cex = 0.5, col = "white", font=2)
}

Some images show minor cloud cover; however, these were the highest-quality sennes avaliable for each year and were therefore selected to ensure consistency arcoss the time series. The following Landsat images highlight the significant growth of Macau’s land area in recent decades.

下列 Landsat 影像展示了澳門自 1990 年以來的明顯填海過程。

par(mfrow = c(2, 4), mar = c(2, 2, 3, 1))

for(i in seq_along(landsat_image_mo_list)){
  landsat_images_mo(i)
}

NDWI

Using Normalized Difference Water Index (NDWI)

NDWI = (Green – NIR)/(Green + NIR)

NDWI <- function(green, NIR){
   value <- (green - NIR) / (green + NIR)
   return(value)
}

The NDWI values correspond to the following ranges:

  • 0,2 – 1 – Water surface,

  • 0.0 – 0,2 – Flooding, humidity,

  • -0,3 – 0.0 – Moderate drought, non-aqueous surfaces,

  • -1 – -0.3 – Drought, non-aqueous surfaces

ndwi_1990 <- NDWI(crop_1990$green, crop_1990$NIR)
ndwi_1995 <- NDWI(crop_1995$green, crop_1995$NIR)
ndwi_2000 <- NDWI(crop_2000$green, crop_2000$NIR)
ndwi_2005 <- NDWI(crop_2005$green, crop_2005$NIR)
ndwi_2010 <- NDWI(crop_2010$green, crop_2010$NIR)
ndwi_2015 <- NDWI(crop_2015$green, crop_2015$NIR)
ndwi_2020 <- NDWI(crop_2020$green, crop_2020$NIR)
ndwi_2025 <- NDWI(crop_2025$green, crop_2025$NIR)

In 1969, a 2.2-kilometer causeway known as Estrada do Istmo (路氹連貫公路) was constructed to connect Taipa and Coloane. After the completion of Estrada do Istmo (路氹連貫公路) causeway, the east-west movement of water and sediment between Taipa and Coloane was obstructed. this alteration in hydrodynamic condition led to accelerated sediment deposition in both side of causeway, especially on the western side. Within a short period, extensive tidal flats emerged, and mangroves proliferated rapidly. These geomorphological changes created favorable conditions for subsequent large-scale land reclamation. (城市格局演變與城市規劃制度研析)

Therefore, the following NDWI image shows that the western side of the causeway exhibits lower NDWI values, indicating significant sediment deposition in that area.

plot(ndwi_1990)
mtext("1990-12-24\nAuthor: Jiatong Su", side = 1, line = -1.5, adj = 0.5, cex = 0.5, col = "white", font=2)

However, this is not as apparent in the visible RGB Landsat imagery, where the western side of the causeway still appears to be normal water.

plotRGB( crop_1990, r = 3, g = 2, b = 1, stretch = "lin") 
mtext("1990-12-24\nAuthor: Jiatong Su", side = 1, line = -1.5, adj = 0.5, cex = 0.5, col = "white", font=2)

stack_ndwi <- stack(ndwi_1990, ndwi_1995, ndwi_2000, ndwi_2005,
                    ndwi_2010, ndwi_2015, ndwi_2020, ndwi_2025)

names(stack_ndwi) <- c("ndwi_1990", "ndwi_1995", "ndwi_2000", "ndwi_2005",
                       "ndwi_2010", "ndwi_2015", "ndwi_2020", "ndwi_2025")
plot(stack_ndwi)

False color

land_mask <- ndwi_rast <= 0

land_mask01 <- classify(land_mask, cbind(0, NA, 1))

land_stack <- c(land_mask01[[1]], land_mask01[[2]], land_mask01[[3]],
                land_mask01[[4]], land_mask01[[5]], land_mask01[[6]],
                land_mask01[[7]], land_mask01[[8]] )

names(land_stack) <- c("land_1990","land_1995","land_2000",
                       "land_2005","land_2010","land_2015",
                       "land_2020","land_2025")

#plotRGB(land_stack, r=3, g=2, b=1,  stretch="lin") # 1995 vs 1990
plotRGB(land_stack, r=4, g=2, b=2,  stretch="lin") # 1995 vs 2025
#mtext( "Created by Jiatong Su", side=1, adj=0.6, line=4, cex=1.5, col = "grey")
#mtext( "2000-09-06", cex.main=1, adj=0.6, cex=2, col = "grey")

 mtext(paste("Date:", "1995 vs 2005", "\nCreated by: Jiatong Su"),
        side = 1,   cex.main=1, adj=0.6, line=4, cex=1.5, col = "white", font=2)

false color 00-10-25

This false-color land-change visualization highlights Macau’s rapid coastal expansion from 2000 to 2025 using multi-temporal Landsat imagery. Red areas represent newly reclaimed land between 2010–2025, yellow between 2000–2010, and white denotes stable land present across all three period.

 # 取得 raster 的座標範圍
e <- terra::ext(land_stack)

 
 # 設定 legend 位置(右下角內縮 5%)
 x_leg <- e$xmax - 0.5 * (e$xmax - e$xmin)
 y_leg <- e$ymax - 0.1 * (e$ymax - e$ymin)  # ymin 是下面 → 往上 20%
 
 # plot
 plotRGB(
   land_stack, r = 8, g = 5, b = 3, stretch = "lin",
  main = "Macau Land Expansion (2000–2010–2025)")

mtext(
  "False-color Representation\nof Macau Land Expansion\n2000 • 2010 • 2025",
   side = 1,       # top
   line = 2,     # move closer to plot (- moves inside)
   adj = 0.6,
   cex = 1.5,
  font = 1,
   col = "white" )
 
 
 # Caption
 mtext(
  "Created by Jiatong Su",
  side = 1,
  line = 4,
  adj = 0.62,
  cex = 1,
  col = "grey")
 
legend(
   x = x_leg,
   y = y_leg,
   legend = c(
     "Change between 2010-2025",
     "Change between 2000-2010",
     "Land in all 3 periods"
     #"Water"
   ),
   fill = c(
     rgb(1,0,0),   # red for 2025
     rgb(1,1,0),   # yellow for 2000-2010
     rgb(1,1,1)   # white in all period
    #rgb(0,0,0)    # black is water 
   ),
   border = NA,
   cex = 0.85,
   bg = NA,
   text.col = "white",
   bty = "n"   )

Interactive map

#only one color represent land,water is NA
pal_land <- colorFactor(
  palette = c("orange"),   
  domain  = c(1),
  na.color = "transparent"
)
years <- c("1990","1995","2000","2005","2010","2015","2020","2025")
layer_names <- names(land_stack)  # "land_1990" ...

m <- leaflet() |>
  addProviderTiles(providers$CartoDB.Positron)  # basemap

# add land mask for each year
for (i in seq_along(layer_names)) {
  m <- m |>
    addRasterImage(
      land_stack[[i]],
      colors  = pal_land,
      opacity = 0.8,
      project = TRUE,                  #  WGS84 - leaflet
      group   = years[i]
    )
}

# layer control(chose year)
m <- m |>
  addLayersControl(
    overlayGroups = years,
    options = layersControlOptions(collapsed = FALSE)
  ) |>
  addControl(
    "NDWI-based Land Mask for Macau (1990–2025)",
    position = "bottomleft"
  )

m  
LS0tDQp0aXRsZTogIk1hY2F1LXJlY2xhbWF0aW9uLXRpbWVzZXJpZXMiICAgDQphdXRob3I6ICJKaWF0b25nIFN1IiAgICAgICAgICAgICAgICAgICAgIA0KDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMg5oyH5a6a6Ly45Ye65qC85byPDQogIGh0bWxfZG9jdW1lbnQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMg5L2/55SoIHJtYXJrZG93bjo6aHRtbF9kb2N1bWVudCgpIOi8uOWHuiBIVE1MDQogICAgdGhlbWU6IHNpbXBsZXggICAgICAgICAgICAgICAgICAgICAgICMg5L2/55SoIEJvb3Rzd2F0Y2gg55qEICdzaW1wbGV4JyDkuLvpoYzmqKPlvI8NCiAgICB0b2M6IHRydWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyDmmK/lkKbpoa/npLrnm67pjIQgKHRhYmxlIG9mIGNvbnRlbnRzKQ0KICAgIHRvY19mbG9hdDogdHJ1ZSAgICAgICAgICAgICAgICAgICAgICAjIOebrumMhOWbuuWumuWcqOWBtOmCiu+8jOaNsuWLlemggemdouaZguacg+i3n+iRl+WLlQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZSAgICAgICAgICAgICAgICAgICAjIFIgY29kZSDpoJDoqK3mkbrnlorvvIzoroDogIXlj6/mjInmjInpiJXlsZXplosNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgICAgICAgICAjIGRvd25sb2FkIFJtZA0KDQpwYXJhbXM6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMga25pdCB3aXRoIHBhcmFtZXRlcnMg55So55qE5Y+D5pW46Kit5a6aDQogIGluY2x1ZGVfd2FybmluZ3M6IGZhbHNlICAgICAgIA0KDQplZGl0b3Jfb3B0aW9uczogICAgICAgICAgICAgICAgICAgICAgICAgICMg5Y+q5b2x6Z+/IFJTdHVkaW8g57eo6Lyv5Zmo77yM5LiN5b2x6Z+/6Ly45Ye657WQ5p6cDQogIG1hcmtkb3duOg0KICAgIHdyYXA6IHNlbnRlbmNlICAgICAgICAgICAgICAgICAjIOWcqCBSU3R1ZGlvIOijoeiHquWLleS+neOAjOWPpeWtkOOAjeaPm+ihjO+8jOaWueS+v+Wvq+mVt+aWhw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KI3JtKGxpc3QgPSBscygpKQ0KI3NldHdkKCdDOi9Vc2Vycy81OTIzOS9EZXNrdG9wL21hY2F1JykNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShzZikNCmxpYnJhcnkoYW5pbWF0aW9uKQ0KbGlicmFyeShtYWdpY2spDQpsaWJyYXJ5KHRlcnJhKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeSh0ZXJyYSkNCmxpYnJhcnkobWFnaWNrKQ0KDQoNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQpNYWNhdSBoYXMgdW5kZXJnb25lIHNpZ25pZmljYW50IGxhbmQgcmVjbGFtYXRpb24gb3ZlciB0aGUgbGFzdCBmZXcgZGVjYWRlcy4NCkR1ZSB0byB1cmJhbiBncm93dGggYW5kIGxpbWl0ZWQgb3JpZ2luYWwgbGFuZCBhcmVhLCByZWNsYW1hdGlvbiBoYXMgcGxheWVkIGEgZG9taW5hbnQgcm9sZSBpbiBzaGFwaW5nIHRoZSBjaXR5J3MgbW9kZXJuIGxhbmRzY2FwZS4NClRoaXMgc3R1ZHkgdXRpbGl6ZXMgTGFuZHNhdCBpbWFnZXJ5IHRvIHZpc3VhbGl6ZSBhbmQgcXVhbnRpZnkgbGFuZCBleHBhbnNpb24gZnJvbSAxOTkwIHRvIDIwMjUsIGV4YW1pbmluZyB0aGUgdGVtcG9yYWwgZXZvbHV0aW9uIG9mIE1hY2F1J3MgbGFuZCBleHRlbnQuDQoNCuacrOeglOeptumBi+eUqCBMYW5kc2F0IOW9seWDj+WRiOePvuS4puWIhuaekOa+s+mWgOmBjuWOu+S4ieWNgeWkmuW5tOS+hueahOWcn+WcsOaTtOW8teOAgg0KDQojIERhdGENCg0KVGhlIFttYWNhdV9nZW9qc29uXShodHRwczovL2dlbzJkYXkuY29tL2FzaWEvY2hpbmEvbWFjYXUuZ2VvanNvbikgd2FzIGRvd25sb2FkZWQgZnJvbSB0aGUgW01hcCBvZiBNYWNhdSBhbmQgR0lTIGRhdGEg4oCUIGRvd25sb2FkIE9TTSB2ZWN0b3IgbGF5ZXJzXShodHRwczovL2dlbzJkYXkuY29tL2FzaWEvY2hpbmEvbWFjYXUuaHRtbCkgYW5kIHVzZWQgYXMgdGhlIHNwYXRpYWwgYm91bmRhcnkgZm9yIGNyb3BwaW5nIHRoZSBMYW5kc2F0IGltYWdlcnkuDQpUaGlzIHBvbHlnb24gYm91bmRhcnkgaXMgdXNlZCB0byBjcm9wIGVhY2ggTGFuZHNhdCBzY2VuZSB0byB0aGUgc3R1ZHkgYXJlYS4NCg0KYGBge3IgbWFjYXVfcG9seWdvbn0NCm1hY2F1X3BvbHlnb24gPC0gc3RfcmVhZCgiaHR0cHM6Ly9nZW8yZGF5LmNvbS9hc2lhL2NoaW5hL21hY2F1Lmdlb2pzb24iKQ0KcGxvdChtYWNhdV9wb2x5Z29uKQ0KYGBgDQoNCiMgTGFuZHNhdCBpbWFnZXJ5IGZyb20gMTk5MC0yMDI1DQoNClRoZSBhbmFseXNpcyB1c2VzIG11bHRpLXRlbXBvcmFsIExhbmRzYXQgaW1hZ2VyeSBmcm9tIDE5OTAtMjAyNSwgZG93bmxvYWRlZCBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzIEdlb2xvZ2ljYWwgU3VydmV5KFVTR1MpIFtFYXJ0aEV4cGxvcmVyXShodHRwczovL2VhcnRoZXhwbG9yZXIudXNncy5nb3YvKSBQbGF0ZnJvbS4NClRoZSBMYW5kc2F0IGRhdGEgb2YgZWFjaCB5ZWFyIGNvbnRhaW5zIG11bHRpcGxlIHNpbmdsZSBiYW5kIGB0aWZgIGZpbGVzLg0KVGhlc2UgYmFuZHMgbXVzdCBiZSBzdGFja2VkIGludG8gYSBtdWx0aS1iYW5kIHJhc3RlciBiZWZvcmUgdmlzdWFsaXphdGlvbiBvciBhbmFseXNpcy4NCkZvciBtb3JlIGRldGFpbCBpbmZvcm1hdGlvbiBhYm91dCBMYW5kc2F0IHNwZWN0cmFsIGJhbmRzLCByZWZlciB0byBbU3BlY3RyYWwgQmFuZHMgYW5kIEFwcGxpY2F0aW9ucyAtIE5BU0EgU2NpZW5jZV0oaHR0cHM6Ly9zY2llbmNlLm5hc2EuZ292L21pc3Npb24vbGFuZHNhdC9zcGVjdHJhbC1iYW5kcy1hbmQtYXBwbGljYXRpb25zLyl7c3R5bGU9ImZvbnQtc2l6ZTogMTFwdDsifS4NCg0KIyMgTGFuZHNhdDRfMTk5MDEyMjQNCg0KW0xhbmRzYXQ0XShodHRwczovL3d3dy51c2dzLmdvdi9sYW5kc2F0LW1pc3Npb25zL2xhbmRzYXQtNCkNCg0KYGBge3IgbGFuZHNhdDRfMTk5MDEyMjR9DQpsYW5kc2F0NF8xOTkwMTIyNCA8LSBzdGFjaygNCiAiTFQwNF9MMlNQXzEyMjA0NV8xOTkwMTIyNF8yMDIwMDkxNV8wMl9UMS9MVDA0X0wyU1BfMTIyMDQ1XzE5OTAxMjI0XzIwMjAwOTE1XzAyX1QxX1NSX0IxLlRJRiIsDQogIkxUMDRfTDJTUF8xMjIwNDVfMTk5MDEyMjRfMjAyMDA5MTVfMDJfVDEvTFQwNF9MMlNQXzEyMjA0NV8xOTkwMTIyNF8yMDIwMDkxNV8wMl9UMV9TUl9CMi5USUYiLA0KICJMVDA0X0wyU1BfMTIyMDQ1XzE5OTAxMjI0XzIwMjAwOTE1XzAyX1QxL0xUMDRfTDJTUF8xMjIwNDVfMTk5MDEyMjRfMjAyMDA5MTVfMDJfVDFfU1JfQjMuVElGIiwNCiAiTFQwNF9MMlNQXzEyMjA0NV8xOTkwMTIyNF8yMDIwMDkxNV8wMl9UMS9MVDA0X0wyU1BfMTIyMDQ1XzE5OTAxMjI0XzIwMjAwOTE1XzAyX1QxX1NSX0I0LlRJRiIsDQogIkxUMDRfTDJTUF8xMjIwNDVfMTk5MDEyMjRfMjAyMDA5MTVfMDJfVDEvTFQwNF9MMlNQXzEyMjA0NV8xOTkwMTIyNF8yMDIwMDkxNV8wMl9UMV9TUl9CNS5USUYiLA0KICJMVDA0X0wyU1BfMTIyMDQ1XzE5OTAxMjI0XzIwMjAwOTE1XzAyX1QxL0xUMDRfTDJTUF8xMjIwNDVfMTk5MDEyMjRfMjAyMDA5MTVfMDJfVDFfU1RfQjYuVElGIiwNCiAiTFQwNF9MMlNQXzEyMjA0NV8xOTkwMTIyNF8yMDIwMDkxNV8wMl9UMS9MVDA0X0wyU1BfMTIyMDQ1XzE5OTAxMjI0XzIwMjAwOTE1XzAyX1QxX1NSX0I3LlRJRiINCg0KKQ0KDQpuYW1lcyhsYW5kc2F0NF8xOTkwMTIyNCkgPC0gYygiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiTklSIiwgIlNXSVIiLCJUaGVybWFsIiwgIk1pZC1JbmZyYXJlZC1JUiIpICNyZW5hbWUgYmFuZHMNCg0KIyBwbG90UkdCKGxhbmRzYXQ0XzE5OTAxMjI0LCByPTMsIGcgPSAyLCBiID0gMSwgc3RyZXRjaCA9ICJsaW4iKQ0KDQpzdW1tYXJ5KGxhbmRzYXQ0XzE5OTAxMjI0KQ0KDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmNycyhsYW5kc2F0NF8xOTkwMTIyNCkNCnN1bW1hcnkobGFuZHNhdDRfMTk5MDEyMjQpDQpgYGANCg0KIyMgTGFuZHNhdDVfMTk5NQ0KDQpbTGFuZHNhdDVdKGh0dHBzOi8vd3d3LnVzZ3MuZ292L2xhbmRzYXQtbWlzc2lvbnMvbGFuZHNhdC01KQ0KDQpgYGB7ciBsYW5kc2F0NV8xOTk1fQ0KbGFuZHNhdDVfMTk5NTEyMzAgPC0gc3RhY2soDQogICJMVDA1X0wyU1BfMTIyMDQ1XzE5OTUxMjMwXzIwMjAwOTExXzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMTk5NTEyMzBfMjAyMDA5MTFfMDJfVDFfU1JfQjEuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMTk5NTEyMzBfMjAyMDA5MTFfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8xOTk1MTIzMF8yMDIwMDkxMV8wMl9UMV9TUl9CMi5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8xOTk1MTIzMF8yMDIwMDkxMV8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzE5OTUxMjMwXzIwMjAwOTExXzAyX1QxX1NSX0IzLlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzE5OTUxMjMwXzIwMjAwOTExXzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMTk5NTEyMzBfMjAyMDA5MTFfMDJfVDFfU1JfQjQuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMTk5NTEyMzBfMjAyMDA5MTFfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8xOTk1MTIzMF8yMDIwMDkxMV8wMl9UMV9TUl9CNS5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8xOTk1MTIzMF8yMDIwMDkxMV8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzE5OTUxMjMwXzIwMjAwOTExXzAyX1QxX1NUX0I2LlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzE5OTUxMjMwXzIwMjAwOTExXzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMTk5NTEyMzBfMjAyMDA5MTFfMDJfVDFfU1JfQjcuVElGIg0KKQ0KDQpuYW1lcyhsYW5kc2F0NV8xOTk1MTIzMCkgPC0gYygiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiTklSIiwgIlNXSVIiLCAiVGhlcm1hbCIsICJNaWQtSW5mcmFyZWQiKSAjcmVuYW1lIGJhbmRzDQoNCnN1bW1hcnkobGFuZHNhdDVfMTk5NTEyMzApDQoNCiNjcnMobGFuZHNhdDVfMTk5NTEyMzApDQoNCmBgYA0KDQojIyBMYW5kc2F0NV8yMDAwDQoNCmBgYHtyIExhbmRzYXQ1XzIwMDB9DQpMYW5kc2F0NV8yMDAwMDkwNiA8LSBzdGFjaygNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAwMDA5MDZfMjAyMDA5MDZfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDAwMDkwNl8yMDIwMDkwNl8wMl9UMV9TUl9CMS5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDAwMDkwNl8yMDIwMDkwNl8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMDAwOTA2XzIwMjAwOTA2XzAyX1QxX1NSX0IyLlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMDAwOTA2XzIwMjAwOTA2XzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAwMDA5MDZfMjAyMDA5MDZfMDJfVDFfU1JfQjMuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAwMDA5MDZfMjAyMDA5MDZfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDAwMDkwNl8yMDIwMDkwNl8wMl9UMV9TUl9CNC5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDAwMDkwNl8yMDIwMDkwNl8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMDAwOTA2XzIwMjAwOTA2XzAyX1QxX1NSX0I1LlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMDAwOTA2XzIwMjAwOTA2XzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAwMDA5MDZfMjAyMDA5MDZfMDJfVDFfU1RfQjYuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAwMDA5MDZfMjAyMDA5MDZfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDAwMDkwNl8yMDIwMDkwNl8wMl9UMV9TUl9CNy5USUYiDQopDQoNCm5hbWVzKExhbmRzYXQ1XzIwMDAwOTA2KSA8LSBjKCJibHVlIiwgImdyZWVuIiwgInJlZCIsICJOSVIiLCAiU1dJUiIsICJUaGVybWFsIiwgIk1pZC1JbmZyYXJlZCIpICNyZW5hbWUgYmFuZHMNCg0Kc3VtbWFyeShMYW5kc2F0NV8yMDAwMDkwNikNCg0KYGBgDQoNCiMjIExhbmRzYXQ1XzIwMDUNCg0KW0xhbmRzYXQ3XShodHRwczovL3d3dy51c2dzLmdvdi9sYW5kc2F0LW1pc3Npb25zL2xhbmRzYXQtNykgY2FuIG5vdCB1c2UNCg0KYGBge3IgTGFuZHNhdDVfMjAwNX0NCkxhbmRzYXQ1XzIwMDUxMDIyIDwtIHN0YWNrKA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDA1MTAyMl8yMDIwMDkwMV8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMDUxMDIyXzIwMjAwOTAxXzAyX1QxX1NSX0IxLlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMDUxMDIyXzIwMjAwOTAxXzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAwNTEwMjJfMjAyMDA5MDFfMDJfVDFfU1JfQjIuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAwNTEwMjJfMjAyMDA5MDFfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDA1MTAyMl8yMDIwMDkwMV8wMl9UMV9TUl9CMy5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDA1MTAyMl8yMDIwMDkwMV8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMDUxMDIyXzIwMjAwOTAxXzAyX1QxX1NSX0I0LlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMDUxMDIyXzIwMjAwOTAxXzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAwNTEwMjJfMjAyMDA5MDFfMDJfVDFfU1JfQjUuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAwNTEwMjJfMjAyMDA5MDFfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDA1MTAyMl8yMDIwMDkwMV8wMl9UMV9TVF9CNi5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDA1MTAyMl8yMDIwMDkwMV8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMDUxMDIyXzIwMjAwOTAxXzAyX1QxX1NSX0I3LlRJRiINCiAgKQ0KDQpuYW1lcyhMYW5kc2F0NV8yMDA1MTAyMikgPC0gYygiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiTklSIiwgIlNXSVIiLCAiVGhlcm1hbCIsICJNaWQtSW5mcmFyZWQiKSAjcmVuYW1lIGJhbmRzDQoNCnN1bW1hcnkoTGFuZHNhdDVfMjAwNTEwMjIpDQoNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnBsb3RSR0IoTGFuZHNhdDVfMjAwNTEwMjIsIHIgPSAzLCBnID0gMiwgYiA9IDEsIHN0cmV0Y2ggPSAibGluIikNCmBgYA0KDQojIyBMYW5kc2F0NV8yMDEwDQoNCmBgYHtyIExhbmRzYXQ1XzIwMTB9DQpMYW5kc2F0NV8yMDEwMDMyNiA8LSBzdGFjaygNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAxMDAzMjZfMjAyMDA4MjRfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDEwMDMyNl8yMDIwMDgyNF8wMl9UMV9TUl9CMS5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDEwMDMyNl8yMDIwMDgyNF8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMTAwMzI2XzIwMjAwODI0XzAyX1QxX1NSX0IyLlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMTAwMzI2XzIwMjAwODI0XzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAxMDAzMjZfMjAyMDA4MjRfMDJfVDFfU1JfQjMuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAxMDAzMjZfMjAyMDA4MjRfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDEwMDMyNl8yMDIwMDgyNF8wMl9UMV9TUl9CNC5USUYiLA0KICAiTFQwNV9MMlNQXzEyMjA0NV8yMDEwMDMyNl8yMDIwMDgyNF8wMl9UMS9MVDA1X0wyU1BfMTIyMDQ1XzIwMTAwMzI2XzIwMjAwODI0XzAyX1QxX1NSX0I1LlRJRiIsDQogICJMVDA1X0wyU1BfMTIyMDQ1XzIwMTAwMzI2XzIwMjAwODI0XzAyX1QxL0xUMDVfTDJTUF8xMjIwNDVfMjAxMDAzMjZfMjAyMDA4MjRfMDJfVDFfU1RfQjYuVElGIiwNCiAgIkxUMDVfTDJTUF8xMjIwNDVfMjAxMDAzMjZfMjAyMDA4MjRfMDJfVDEvTFQwNV9MMlNQXzEyMjA0NV8yMDEwMDMyNl8yMDIwMDgyNF8wMl9UMV9TUl9CNy5USUYiDQopDQoNCm5hbWVzKExhbmRzYXQ1XzIwMTAwMzI2KSA8LSBjKCJibHVlIiwgImdyZWVuIiwgInJlZCIsICJOSVIiLCAiU1dJUiIsICJUaGVybWFsIiwgIk1pZC1JbmZyYXJlZCIpICNyZW5hbWUgYmFuZHMNCg0Kc3VtbWFyeShMYW5kc2F0NV8yMDEwMDMyNikNCmBgYA0KDQojIyBMYW5kc2F0OF8yMDE1DQoNCltMYW5kc2F0OF0oaHR0cHM6Ly93d3cudXNncy5nb3YvbGFuZHNhdC1taXNzaW9ucy9sYW5kc2F0LTgpDQoNCmBgYHtyIExhbmRzYXQ4XzIwMTV9DQpMYW5kc2F0OF8yMDE1MTAxOCA8LSBzdGFjaygNCiAjIkxDMDhfTDJTUF8xMjIwNDVfMjAxNTEwMThfMjAyMDA5MDhfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMV9TUl9CMS5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMTUxMDE4XzIwMjAwOTA4XzAyX1QxX1NSX0IyLlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMTUxMDE4XzIwMjAwOTA4XzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAxNTEwMThfMjAyMDA5MDhfMDJfVDFfU1JfQjMuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAxNTEwMThfMjAyMDA5MDhfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMV9TUl9CNC5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMTUxMDE4XzIwMjAwOTA4XzAyX1QxX1NSX0I1LlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMTUxMDE4XzIwMjAwOTA4XzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAxNTEwMThfMjAyMDA5MDhfMDJfVDFfU1JfQjYuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAxNTEwMThfMjAyMDA5MDhfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMV9TUl9CNy5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDE1MTAxOF8yMDIwMDkwOF8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMTUxMDE4XzIwMjAwOTA4XzAyX1QxX1NUX0IxMC5USUYiDQopDQoNCm5hbWVzKExhbmRzYXQ4XzIwMTUxMDE4KSA8LSBjKCAiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiTklSIiwgIlNXSVIiLCAiU1dJUjIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUSVJTMSIpICNyZW5hbWUgYmFuZHMNCg0KI1RoZXJtYWwgSW5mcmFyZWQgU2Vuc29yIChUSVJTKTogQmFuZCAxMCBUSVJTIDEgKDEwLjYgLSAxMS4xOSDCtW0pIDEwMCBtDQojIkNvYXN0YWwiID0gQmFuZCAxDQpzdW1tYXJ5KExhbmRzYXQ4XzIwMTUxMDE4KQ0KYGBgDQoNCiMjIExhbmRzYXQ4XzIwMjANCg0KYGBge3IgTGFuZHNhdDhfMjAyMH0NCkxhbmRzYXQ4XzIwMjAxMjAyIDwtIHN0YWNrKA0KICMiTEMwOF9MMlNQXzEyMjA0NV8yMDIwMTIwMl8yMDIxMDMxMl8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxX1NSX0IxLlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAyMDEyMDJfMjAyMTAzMTJfMDJfVDFfU1JfQjIuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAyMDEyMDJfMjAyMTAzMTJfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDIwMTIwMl8yMDIxMDMxMl8wMl9UMV9TUl9CMy5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDIwMTIwMl8yMDIxMDMxMl8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxX1NSX0I0LlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAyMDEyMDJfMjAyMTAzMTJfMDJfVDFfU1JfQjUuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAyMDEyMDJfMjAyMTAzMTJfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDIwMTIwMl8yMDIxMDMxMl8wMl9UMV9TUl9CNi5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDIwMTIwMl8yMDIxMDMxMl8wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxX1NSX0I3LlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMjAxMjAyXzIwMjEwMzEyXzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAyMDEyMDJfMjAyMTAzMTJfMDJfVDFfU1RfQjEwLlRJRiINCikNCg0KDQpuYW1lcyhMYW5kc2F0OF8yMDIwMTIwMikgPC0gYyggImJsdWUiLCAiZ3JlZW4iLCAicmVkIiwgIk5JUiIsICJTV0lSIiwgIlNXSVIyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVElSUzEiKSAjcmVuYW1lIGJhbmRzDQoNCiNUaGVybWFsIEluZnJhcmVkIFNlbnNvciAoVElSUyk6IEJhbmQgMTAgVElSUyAxICgxMC42IC0gMTEuMTkgwrVtKSAxMDAgbQ0KDQpzdW1tYXJ5KExhbmRzYXQ4XzIwMjAxMjAyKQ0KYGBgDQoNCiMjIExhbmRzYXQ4XzIwMjUwMzI3DQoNCmBgYHtyIExhbmRzYXQ4XzIwMjUwMzI3fQ0KTGFuZHNhdDhfMjAyNTAzMjcgPC0gc3RhY2soDQojIkxDMDhfTDJTUF8xMjIwNDVfMjAyNTAzMTlfMjAyNTAzMjdfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMV9TUl9CMS5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjUwMzE5XzIwMjUwMzI3XzAyX1QxX1NSX0IyLlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMjUwMzE5XzIwMjUwMzI3XzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAyNTAzMTlfMjAyNTAzMjdfMDJfVDFfU1JfQjMuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAyNTAzMTlfMjAyNTAzMjdfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMV9TUl9CNC5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjUwMzE5XzIwMjUwMzI3XzAyX1QxX1NSX0I1LlRJRiIsDQogICJMQzA4X0wyU1BfMTIyMDQ1XzIwMjUwMzE5XzIwMjUwMzI3XzAyX1QxL0xDMDhfTDJTUF8xMjIwNDVfMjAyNTAzMTlfMjAyNTAzMjdfMDJfVDFfU1JfQjYuVElGIiwNCiAgIkxDMDhfTDJTUF8xMjIwNDVfMjAyNTAzMTlfMjAyNTAzMjdfMDJfVDEvTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMV9TUl9CNy5USUYiLA0KICAiTEMwOF9MMlNQXzEyMjA0NV8yMDI1MDMxOV8yMDI1MDMyN18wMl9UMS9MQzA4X0wyU1BfMTIyMDQ1XzIwMjUwMzE5XzIwMjUwMzI3XzAyX1QxX1NUX0IxMC5USUYiDQopDQoNCm5hbWVzKExhbmRzYXQ4XzIwMjUwMzI3KSA8LSBjKCAiYmx1ZSIsICJncmVlbiIsICJyZWQiLCAiTklSIiwgIlNXSVIiLCAiU1dJUjIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUSVJTMSIpICNyZW5hbWUgYmFuZHMNCg0KDQpzdW1tYXJ5KExhbmRzYXQ4XzIwMjUwMzI3KQ0KDQpgYGANCg0KIyBDcm9wDQoNClRoaXMgc2VjdGlvbiB1c2UgbWFjYXUgYm91bmRhcnkgcG9seWdvbiB0byBjcm9wIHRoZSBzdHVkeSBhcmVhIGZyb20gZWFjaCB5ZWFyIExhbmRzYXQgc3RhY2tlZCBpbWFnZS4NCg0KYGBge3J9DQptYWNhdV9wb2x5X3V0bSA8LSBzdF90cmFuc2Zvcm0obWFjYXVfcG9seWdvbiwgY3JzID0gY3JzKExhbmRzYXQ1XzIwMDUxMDIyKSkNCiMgbWF0Y2ggdGhlIHByb2plY3Rpb24NCmBgYA0KDQpgYGB7ciBjcm9wfQ0KY3JvcF8xOTkwIDwtIGNyb3AobGFuZHNhdDRfMTk5MDEyMjQsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8xOTk1IDwtIGNyb3AobGFuZHNhdDVfMTk5NTEyMzAsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDAwIDwtIGNyb3AoTGFuZHNhdDVfMjAwMDA5MDYsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDA1IDwtIGNyb3AoTGFuZHNhdDVfMjAwNTEwMjIsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDEwIDwtIGNyb3AoTGFuZHNhdDVfMjAxMDAzMjYsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDE1IDwtIGNyb3AoTGFuZHNhdDhfMjAxNTEwMTgsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDIwIDwtIGNyb3AoTGFuZHNhdDhfMjAyMDEyMDIsIG1hY2F1X3BvbHlfdXRtKQ0KY3JvcF8yMDI1IDwtIGNyb3AoTGFuZHNhdDhfMjAyNTAzMjcsIG1hY2F1X3BvbHlfdXRtKQ0KDQoNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnBsb3RSR0IoIGNyb3BfMTk5MCwgciA9IDMsIGcgPSAyLCBiID0gMSwgc3RyZXRjaCA9ICJsaW4iKSANCm10ZXh0KCIxOTkwLTEyLTI0XG5BdXRob3I6IEppYXRvbmcgU3UiLCBzaWRlID0gMSwgbGluZSA9IC0xLjUsIGFkaiA9IDAuNSwgY2V4ID0gMC41LCBjb2wgPSAid2hpdGUiLCBmb250PTIpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpwbG90UkdCKCBjcm9wXzIwMjUsIHIgPSAzLCBnID0gMiwgYiA9IDEsIHN0cmV0Y2ggPSAibGluIikgDQptdGV4dCgiMjAyNS0wMy0yN1xuQXV0aG9yOiBKaWF0b25nIFN1Iiwgc2lkZSA9IDEsIGxpbmUgPSAtMS41LCBhZGogPSAwLjUsIGNleCA9IDAuNSwgY29sID0gIndoaXRlIiwgZm9udD0yKQ0KDQpgYGANCg0KIyBWaXN1YWxpemF0aW9uDQoNClRydWUgY29sb3IgY29tcG9zaXRlcyB3ZXJlIGdlbmVyYXRlZCBmb3IgZWFjaCB5ZWFyIHVzaW5nIGJhbmQgY29tYmluYXRpb25zIChlLmcuLCBSID0gUmVkLCBHID0gR3JlZW4sIEIgPSBCbHVlKS4NCg0KYGBge3J9DQpsYW5kc2F0X2ltYWdlX21vX2xpc3QgPC0gbGlzdChjcm9wXzE5OTAsIGNyb3BfMTk5NSwgY3JvcF8yMDAwLCBjcm9wXzIwMDUsIGNyb3BfMjAxMCwNCiAgICAgICAgICAgICAgICAgIGNyb3BfMjAxNSwgY3JvcF8yMDIwLCBjcm9wXzIwMjUpDQoNCg0KbGF5ZXJfZGF0ZSA8LSBjKCIxOTkwLTEyLTI0IiwgIjE5OTUtMTItMzAiLCAiMjAwMC0wOS0wNiIsICIyMDA1LTEyLTE3IiwNCiAgICAgICAgICAgICAgIjIwMTAtMTAtMjgiLCAiMjAxNS0xMC0xOCIsICIyMDIwLTEyLTAyIiwgIjIwMjUtMDMtMjciKQ0KDQoNCmxhbmRzYXRfaW1hZ2VzX21vIDwtIGZ1bmN0aW9uKGkpew0KICBwbG90UkdCKGxhbmRzYXRfaW1hZ2VfbW9fbGlzdFtbaV1dLCByID0gMywgZyA9IDIsIGIgPSAxLCBzdHJldGNoID0gImxpbiIpDQogIG10ZXh0KHBhc3RlKCJEYXRlOiIsIGxheWVyX2RhdGVbaV0sICJcbkNyZWF0ZWQgYnk6IEppYXRvbmcgU3UiKSwNCiAgICAgICAgc2lkZSA9IDEsIGxpbmUgPSAtMS41LCBhZGogPSAwLjUsIGNleCA9IDAuNSwgY29sID0gIndoaXRlIiwgZm9udD0yKQ0KfQ0KDQoNCmBgYA0KDQpTb21lIGltYWdlcyBzaG93IG1pbm9yIGNsb3VkIGNvdmVyOyBob3dldmVyLCB0aGVzZSB3ZXJlIHRoZSBoaWdoZXN0LXF1YWxpdHkgc2VubmVzIGF2YWxpYWJsZSBmb3IgZWFjaCB5ZWFyIGFuZCB3ZXJlIHRoZXJlZm9yZSBzZWxlY3RlZCB0byBlbnN1cmUgY29uc2lzdGVuY3kgYXJjb3NzIHRoZSB0aW1lIHNlcmllcy4NClRoZSBmb2xsb3dpbmcgTGFuZHNhdCBpbWFnZXMgaGlnaGxpZ2h0IHRoZSBzaWduaWZpY2FudCBncm93dGggb2YgTWFjYXXigJlzIGxhbmQgYXJlYSBpbiByZWNlbnQgZGVjYWRlcy4NCg0K5LiL5YiXIExhbmRzYXQg5b2x5YOP5bGV56S65LqG5r6z6ZaA6IeqIDE5OTAg5bm05Lul5L6G55qE5piO6aGv5aGr5rW36YGO56iL44CCDQoNCmBgYHtyIHZpc3VhbGl6YXRpb24gZm9yIHZpc2libGUgTGFuZHNhdCBpbWFnZX0NCg0KDQpwYXIobWZyb3cgPSBjKDIsIDQpLCBtYXIgPSBjKDIsIDIsIDMsIDEpKQ0KDQpmb3IoaSBpbiBzZXFfYWxvbmcobGFuZHNhdF9pbWFnZV9tb19saXN0KSl7DQogIGxhbmRzYXRfaW1hZ2VzX21vKGkpDQp9DQoNCg0KYGBgDQoNCg0KDQoNCmBgYHtyIHNhdmUgR0lGLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShhbmltYXRpb24pDQoNCiNUaGUgYGFuaW1hdGlvbmAgZnVuY3Rpb24gaXMgdXNlZCB0byBnZW5lcmF0ZWQgYSBtdWx0aS15ZWFyIGBHSUZgIGlsbHVzdHJhdGluZyB0aGUgcHJvZ3Jzc2lvbiBvZiBsYW5kIGRldmVsb3BtZW50IGFuZCByZWNsYW1hdGlvbiBmcm9tIDE5OTAgdG8gMjAyNS4NCg0Kc2F2ZUdJRih7DQogIGZvciAoaSBpbiBzZXFfYWxvbmcobGFuZHNhdF9pbWFnZV9tb19saXN0KSkgew0KICAgIHBsb3RSR0IobGFuZHNhdF9pbWFnZV9tb19saXN0W1tpXV0sIHIgPSAzLCBnID0gMiwgYiA9IDEsIHN0cmV0Y2ggPSAibGluIikNCiAgICBtdGV4dChwYXN0ZSgiRGF0ZToiLCBsYXllcl9kYXRlW2ldLCAiXG5DcmVhdGVkIGJ5OiBKaWF0b25nIFN1IiksDQogICAgICAgIHNpZGUgPSAxLCBsaW5lID0gLTEuNSwgYWRqID0gMC41LCBjZXggPSAxLjUsIGNvbCA9ICJ3aGl0ZSIsIGZvbnQ9MikNCiAgfQ0KfSwgDQptb3ZpZS5uYW1lID0gIm1hY2F1XzE5OTBfMjAyNS5naWYiLA0KaW50ZXJ2YWwgPSAxLA0KYW5pLndpZHRoID0gODAwLA0KYW5pLmhlaWdodCA9IDgwMA0KKQ0KDQoNCmBgYA0KDQoNCiMgTkRXSQ0KDQpbVXNpbmcgTm9ybWFsaXplZCBEaWZmZXJlbmNlIFdhdGVyIEluZGV4IChORFdJKV0oaHR0cHM6Ly9zdG9yeW1hcHMuYXJjZ2lzLmNvbS9zdG9yaWVzL2Y5NGY1MGMwNWZhMjQ2Njc4NDhiNGI1MWFmNjE0OTM1KQ0KDQoqTkRXSSA9IChHcmVlbiDigJMgTklSKS8oR3JlZW4gKyBOSVIpKg0KDQpgYGB7ciBORFdJIGZ1bmN0aW9ufQ0KDQpORFdJIDwtIGZ1bmN0aW9uKGdyZWVuLCBOSVIpew0KICAgdmFsdWUgPC0gKGdyZWVuIC0gTklSKSAvIChncmVlbiArIE5JUikNCiAgIHJldHVybih2YWx1ZSkNCn0NCg0KYGBgDQoNCioqVGhlIE5EV0kgdmFsdWVzIGNvcnJlc3BvbmQgdG8gdGhlIGZvbGxvd2luZyByYW5nZXM6KioNCg0KLSAgIDAsMiDigJMgMSDigJMgV2F0ZXIgc3VyZmFjZSwNCg0KLSAgIDAuMCDigJMgMCwyIOKAkyBGbG9vZGluZywgaHVtaWRpdHksDQoNCi0gICAtMCwzIOKAkyAwLjAg4oCTIE1vZGVyYXRlIGRyb3VnaHQsIG5vbi1hcXVlb3VzIHN1cmZhY2VzLA0KDQotICAgLTEg4oCTIC0wLjMg4oCTIERyb3VnaHQsIG5vbi1hcXVlb3VzIHN1cmZhY2VzDQoNCmBgYHtyIE5EV0kgfQ0KbmR3aV8xOTkwIDwtIE5EV0koY3JvcF8xOTkwJGdyZWVuLCBjcm9wXzE5OTAkTklSKQ0KbmR3aV8xOTk1IDwtIE5EV0koY3JvcF8xOTk1JGdyZWVuLCBjcm9wXzE5OTUkTklSKQ0KbmR3aV8yMDAwIDwtIE5EV0koY3JvcF8yMDAwJGdyZWVuLCBjcm9wXzIwMDAkTklSKQ0KbmR3aV8yMDA1IDwtIE5EV0koY3JvcF8yMDA1JGdyZWVuLCBjcm9wXzIwMDUkTklSKQ0KbmR3aV8yMDEwIDwtIE5EV0koY3JvcF8yMDEwJGdyZWVuLCBjcm9wXzIwMTAkTklSKQ0KbmR3aV8yMDE1IDwtIE5EV0koY3JvcF8yMDE1JGdyZWVuLCBjcm9wXzIwMTUkTklSKQ0KbmR3aV8yMDIwIDwtIE5EV0koY3JvcF8yMDIwJGdyZWVuLCBjcm9wXzIwMjAkTklSKQ0KbmR3aV8yMDI1IDwtIE5EV0koY3JvcF8yMDI1JGdyZWVuLCBjcm9wXzIwMjUkTklSKQ0KDQoNCmBgYA0KDQpJbiAxOTY5LCBhIDIuMi1raWxvbWV0ZXIgY2F1c2V3YXkga25vd24gYXMgWypFc3RyYWRhIGRvIElzdG1vKiAo6Lev5rC56YCj6LKr5YWs6LevKV0oaHR0cHM6Ly96aC53aWtpcGVkaWEub3JnL3poLW1vLyVFOCVCNyVBRiVFNiVCMCVCOSVFOSU4MCVBMyVFOCVCMiVBQiVFNSU4NSVBQyVFOCVCNyVBRikgd2FzIGNvbnN0cnVjdGVkIHRvIGNvbm5lY3QgW1RhaXBhXShodHRwczovL3poLndpa2lwZWRpYS5vcmcvemgtbW8vJUU2JUIwJUI5JUU0JUJCJTk0KSBhbmQgW0NvbG9hbmVdKGh0dHBzOi8vemgud2lraXBlZGlhLm9yZy96aC1tby8lRTglQjclQUYlRTclOTIlQjApLg0KQWZ0ZXIgdGhlIGNvbXBsZXRpb24gb2YgWypFc3RyYWRhIGRvIElzdG1vKiAo6Lev5rC56YCj6LKr5YWs6LevKV0oaHR0cHM6Ly96aC53aWtpcGVkaWEub3JnL3poLW1vLyVFOCVCNyVBRiVFNiVCMCVCOSVFOSU4MCVBMyVFOCVCMiVBQiVFNSU4NSVBQyVFOCVCNyVBRikgY2F1c2V3YXksIHRoZSBlYXN0LXdlc3QgbW92ZW1lbnQgb2Ygd2F0ZXIgYW5kIHNlZGltZW50IGJldHdlZW4gW1RhaXBhXShodHRwczovL3poLndpa2lwZWRpYS5vcmcvemgtbW8vJUU2JUIwJUI5JUU0JUJCJTk0KSBhbmQgW0NvbG9hbmVdKGh0dHBzOi8vemgud2lraXBlZGlhLm9yZy96aC1tby8lRTglQjclQUYlRTclOTIlQjApIHdhcyBvYnN0cnVjdGVkLg0KdGhpcyBhbHRlcmF0aW9uIGluIGh5ZHJvZHluYW1pYyBjb25kaXRpb24gbGVkIHRvIGFjY2VsZXJhdGVkIHNlZGltZW50IGRlcG9zaXRpb24gaW4gYm90aCBzaWRlIG9mIGNhdXNld2F5LCBlc3BlY2lhbGx5IG9uIHRoZSB3ZXN0ZXJuIHNpZGUuDQpXaXRoaW4gYSBzaG9ydCBwZXJpb2QsIGV4dGVuc2l2ZSB0aWRhbCBmbGF0cyBlbWVyZ2VkLCBhbmQgbWFuZ3JvdmVzIHByb2xpZmVyYXRlZCByYXBpZGx5Lg0KVGhlc2UgZ2VvbW9ycGhvbG9naWNhbCBjaGFuZ2VzIGNyZWF0ZWQgZmF2b3JhYmxlIGNvbmRpdGlvbnMgZm9yIHN1YnNlcXVlbnQgbGFyZ2Utc2NhbGUgbGFuZCByZWNsYW1hdGlvbi4NCihb5Z+O5biC5qC85bGA5ryU6K6K6IiH5Z+O5biC6KaP5YqD5Yi25bqm56CU5p6QXShodHRwczovL3d3dy5oZXJpdGFnZS5tby91cGxvYWRzL3VlZGl0b3IvZmlsZS8yMDI1MDEwOS8xNzM2NDEyODY4NjIwOTU1LnBkZj91dG1fc291cmNlPWNoYXRncHQuY29tKSkNCg0KVGhlcmVmb3JlLCB0aGUgZm9sbG93aW5nIE5EV0kgaW1hZ2Ugc2hvd3MgdGhhdCB0aGUgd2VzdGVybiBzaWRlIG9mIHRoZSBjYXVzZXdheSBleGhpYml0cyBsb3dlciBORFdJIHZhbHVlcywgaW5kaWNhdGluZyBzaWduaWZpY2FudCBzZWRpbWVudCBkZXBvc2l0aW9uIGluIHRoYXQgYXJlYS4NCg0KYGBge3IgbmR3aV8xOTkwfQ0KcGxvdChuZHdpXzE5OTApDQptdGV4dCgiMTk5MC0xMi0yNFxuQXV0aG9yOiBKaWF0b25nIFN1Iiwgc2lkZSA9IDEsIGxpbmUgPSAtMS41LCBhZGogPSAwLjUsIGNleCA9IDAuNSwgY29sID0gIndoaXRlIiwgZm9udD0yKQ0KYGBgDQoNCkhvd2V2ZXIsIHRoaXMgaXMgbm90IGFzIGFwcGFyZW50IGluIHRoZSB2aXNpYmxlIFJHQiBMYW5kc2F0IGltYWdlcnksIHdoZXJlIHRoZSB3ZXN0ZXJuIHNpZGUgb2YgdGhlIGNhdXNld2F5IHN0aWxsIGFwcGVhcnMgdG8gYmUgbm9ybWFsIHdhdGVyLg0KDQpgYGB7ciB2aXNpYmxlIDE5OTB9DQpwbG90UkdCKCBjcm9wXzE5OTAsIHIgPSAzLCBnID0gMiwgYiA9IDEsIHN0cmV0Y2ggPSAibGluIikgDQptdGV4dCgiMTk5MC0xMi0yNFxuQXV0aG9yOiBKaWF0b25nIFN1Iiwgc2lkZSA9IDEsIGxpbmUgPSAtMS41LCBhZGogPSAwLjUsIGNleCA9IDAuNSwgY29sID0gIndoaXRlIiwgZm9udD0yKQ0KYGBgDQoNCmBgYHtyIHN0YWNrIG5kd2l9DQpzdGFja19uZHdpIDwtIHN0YWNrKG5kd2lfMTk5MCwgbmR3aV8xOTk1LCBuZHdpXzIwMDAsIG5kd2lfMjAwNSwNCiAgICAgICAgICAgICAgICAgICAgbmR3aV8yMDEwLCBuZHdpXzIwMTUsIG5kd2lfMjAyMCwgbmR3aV8yMDI1KQ0KDQpuYW1lcyhzdGFja19uZHdpKSA8LSBjKCJuZHdpXzE5OTAiLCAibmR3aV8xOTk1IiwgIm5kd2lfMjAwMCIsICJuZHdpXzIwMDUiLA0KICAgICAgICAgICAgICAgICAgICAgICAibmR3aV8yMDEwIiwgIm5kd2lfMjAxNSIsICJuZHdpXzIwMjAiLCAibmR3aV8yMDI1IikNCmBgYA0KDQpgYGB7ciBwbG90IHN0YWNrIG5kd2l9DQpwbG90KHN0YWNrX25kd2kpDQpgYGANCg0KIyBGYWxzZSBjb2xvcg0KDQpgYGB7ciByYXN0LCBpbmNsdWRlPUZBTFNFfQ0KbmR3aV9yYXN0IDwtIHJhc3Qoc3RhY2tfbmR3aSkNCg0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpwbG90UkdCKG5kd2lfcmFzdCwgciA9IDMsIGcgPSAxLCBiID0gMywgc3RyZXRjaCA9ICJsaW4iKSAjIDIwMDAgdnMgMjAyNQ0KYGBgDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpwbG90UkdCKG5kd2lfcmFzdCwgciA9IDMsIGcgPSA4LCBiID0gMywgc3RyZXRjaCA9ICJsaW4iKSAjIDIwMDAgdnMgMjAyNQ0KYGBgDQoNCmBgYHtyfQ0KbGFuZF9tYXNrIDwtIG5kd2lfcmFzdCA8PSAwDQoNCmxhbmRfbWFzazAxIDwtIGNsYXNzaWZ5KGxhbmRfbWFzaywgY2JpbmQoMCwgTkEsIDEpKQ0KDQpsYW5kX3N0YWNrIDwtIGMobGFuZF9tYXNrMDFbWzFdXSwgbGFuZF9tYXNrMDFbWzJdXSwgbGFuZF9tYXNrMDFbWzNdXSwNCiAgICAgICAgICAgICAgICBsYW5kX21hc2swMVtbNF1dLCBsYW5kX21hc2swMVtbNV1dLCBsYW5kX21hc2swMVtbNl1dLA0KICAgICAgICAgICAgICAgIGxhbmRfbWFzazAxW1s3XV0sIGxhbmRfbWFzazAxW1s4XV0gKQ0KDQpuYW1lcyhsYW5kX3N0YWNrKSA8LSBjKCJsYW5kXzE5OTAiLCJsYW5kXzE5OTUiLCJsYW5kXzIwMDAiLA0KICAgICAgICAgICAgICAgICAgICAgICAibGFuZF8yMDA1IiwibGFuZF8yMDEwIiwibGFuZF8yMDE1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgImxhbmRfMjAyMCIsImxhbmRfMjAyNSIpDQoNCiNwbG90UkdCKGxhbmRfc3RhY2ssIHI9MywgZz0yLCBiPTEsICBzdHJldGNoPSJsaW4iKSAjIDE5OTUgdnMgMTk5MA0KDQoNCmBgYA0KDQpgYGB7cn0NCnBsb3RSR0IobGFuZF9zdGFjaywgcj00LCBnPTIsIGI9MiwgIHN0cmV0Y2g9ImxpbiIpICMgMTk5NSB2cyAyMDI1DQojbXRleHQoICJDcmVhdGVkIGJ5IEppYXRvbmcgU3UiLCBzaWRlPTEsIGFkaj0wLjYsIGxpbmU9NCwgY2V4PTEuNSwgY29sID0gImdyZXkiKQ0KI210ZXh0KCAiMjAwMC0wOS0wNiIsIGNleC5tYWluPTEsIGFkaj0wLjYsIGNleD0yLCBjb2wgPSAiZ3JleSIpDQoNCiBtdGV4dChwYXN0ZSgiRGF0ZToiLCAiMTk5NSB2cyAyMDA1IiwgIlxuQ3JlYXRlZCBieTogSmlhdG9uZyBTdSIpLA0KICAgICAgICBzaWRlID0gMSwgICBjZXgubWFpbj0xLCBhZGo9MC42LCBsaW5lPTQsIGNleD0xLjUsIGNvbCA9ICJ3aGl0ZSIsIGZvbnQ9MikNCg0KYGBgDQoNCg0KYGBge3IgRmFsc2UgY29sb3IgZ2lmLCBpbmNsdWRlPUZBTFNFfQ0KDQptYWtlX3JnYl9naWYgPC0gZnVuY3Rpb24oc3RhY2ssIGJhbmRzLCB0aXRsZXMsIG91dGZpbGU9InJnYl90aW1lc2VyaWVzLmdpZiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MTAwMCwgaGVpZ2h0PTEwMDAsIGZwcz0xLCBhdXRob3I9IkNyZWF0ZWQgYnkgSmlhdG9uZyBTdSIpIHsNCiAgDQogIHBuZ19maWxlcyA8LSBjKCkNCiAgDQogIGZvciAoaSBpbiBzZXFfYWxvbmcoYmFuZHMpKSB7DQogICAgDQogICAgIyDmqpTlkI0NCiAgICBmbmFtZSA8LSBwYXN0ZTAoInJnYl8iLCBiYW5kc1tpXSwgIi5wbmciKQ0KICAgIHBuZyhmbmFtZSwgd2lkdGg9d2lkdGgsIGhlaWdodD1oZWlnaHQpDQogICAgDQogICAgIyDnlasgUkdCIOWclg0KICAgIHBsb3RSR0Ioc3RhY2ssIHI9YmFuZHNbaV0sIGc9MiwgYj0yLCBzdHJldGNoPSJsaW4iKQ0KICAgIA0KICAgIG10ZXh0KHBhc3RlKCJEYXRlOiIsIHRpdGxlc1tpXSwgIlxuQ3JlYXRlZCBieTogSmlhdG9uZyBTdSIpLA0KICAgICAgICBzaWRlID0gMSwgbGluZSA9IDQsIGFkaiA9IDAuNiwgY2V4ID0gMiwgY29sID0gIndoaXRlIiwgZm9udD0yKQ0KICAgIGRldi5vZmYoKQ0KICAgIA0KICAgIA0KICAgIHBuZ19maWxlcyA8LSBjKHBuZ19maWxlcywgZm5hbWUpDQogIH0NCiAgDQogICMg6K6A5YWlIFBORyDkuKblkIjmiJAgR0lGDQogIGltZ3MgPC0gaW1hZ2VfcmVhZChwbmdfZmlsZXMpDQogIGdpZiA8LSBpbWFnZV9hbmltYXRlKGltYWdlX2pvaW4oaW1ncyksIGZwcz1mcHMpDQogIGltYWdlX3dyaXRlKGdpZiwgb3V0ZmlsZSkNCiAgDQogIG1lc3NhZ2UoIkdJRiBzYXZlZCBhczogIiwgb3V0ZmlsZSkNCn0NCg0KYGBgDQoNCmBgYHtyIHNhdmUgRmFsc2UgY29sb3IgZ2lmLCBpbmNsdWRlPUZBTFNFfQ0KbWFrZV9yZ2JfZ2lmKA0KICBzdGFjayA9IGxhbmRfc3RhY2ssDQogIGJhbmRzID0gYygyLDQsNiw4KSwgICAgICAgICAgICAgICAgICMg5L2g55qEIHIgPSAyLDQsNiw4DQogIHRpdGxlcyA9IGMoIjE5OTUtMTItMzAiLCAiMjAwMC0wOS0wNiIsICIyMDEwLTEwLTI4IiwgIjIwMjUtMDMtMjciKSwgICAjIOavj+W8tSBQTkcg55qE5qiZ6aGMDQogIG91dGZpbGUgPSAibXlfcmdiLmdpZiIsDQogIGZwcyA9IDEsDQogIGF1dGhvciA9ICJDcmVhdGVkIGJ5IEppYXRvbmcgU3UiDQopDQoNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCg0KcGxvdFJHQigNCiAgbGFuZF9zdGFjaywgciA9IDEsIGcgPSAyLCBiID0gMywgc3RyZXRjaCA9ICJsaW4iLA0KICBtYWluID0gIk1hY2F1IExhbmQgRXhwYW5zaW9uICgyMDAw4oCTMjAxMOKAkzIwMjUpIg0KKSANCm10ZXh0KA0KICAiRmFsc2UtY29sb3IgcmVwcmVzZW50YXRpb24gb2YgbGFuZCBleHBhbnNpb24uXG5SZWQgPSBOZXcgbGFuZCAoMjAyNSkgXG4gR3JlZW4gPSBsYW5kIGFzIG9mIDIwMTAgXG4gQmx1ZSA9IGxhbmQgYXMgb2YgMjAwMC5cbkNyZWF0ZWQgYnkgSmlhdG9uZyBTdSIsDQogIHNpZGUgPSAxLCBsaW5lID0gNCwgYWRqID0gMC42LCBjZXggPSAwLjcsIGNvbCA9ICJ3aGl0ZSINCikNCmxlZ2VuZCgNCiAgInRvcHJpZ2h0IiwNCiAgbGVnZW5kID0gYygNCiAgICAiTmV3IGxhbmQgKDIwMjUgb25seSkiLA0KICAgICJMYW5kIDIwMTDigJMyMDI1IiwNCiAgICAiTGFuZCAyMDAw4oCTMjAyNSIsDQogICAgIkxhbmQgaW4gYWxsIDMgcGVyaW9kcyIsDQogICAgIldhdGVyIg0KICApLA0KICBmaWxsID0gYygNCiAgICByZ2IoMSwwLDEpLCAgICMg57SrL+a0i+e0hSA9IOaWsOWhq+a1t++8iFI9MSxHPTAsQj0x77yJDQogICAgcmdiKDEsMSwwKSwgICAjIOm7g+iJsiA9IDIwMTAg6IiHIDIwMjUg6YO95piv6Zm45Zyw77yIUj0xLEc9MSxCPTDvvIkNCiAgICByZ2IoMCwxLDEpLCAgICMg6Z2S6ImyID0gMjAwMCAmIDIwMTAgJiAyMDI177yI5Zyo5r6z6ZaA5bm+5LmO5LiN5Ye654++77yJDQogICAgcmdiKDEsMSwxKSwgICAjIOeZveiJsiA9IOWFqOaZguacn+mDveaYr+mZuOWcsA0KICAgIHJnYigwLDAsMCkgICAgIyDpu5HoibIgPSDmtbcNCiAgKSwNCiAgYm9yZGVyID0gTkEsDQogIGNleCA9IDAuOCwNCiAgYmcgPSAid2hpdGUiDQoNCikNCg0KYGBgDQoNCiMjIGZhbHNlIGNvbG9yIDAwLTEwLTI1DQoNClRoaXMgZmFsc2UtY29sb3IgbGFuZC1jaGFuZ2UgdmlzdWFsaXphdGlvbiBoaWdobGlnaHRzIE1hY2F14oCZcyByYXBpZCBjb2FzdGFsIGV4cGFuc2lvbiBmcm9tIDIwMDAgdG8gMjAyNSB1c2luZyBtdWx0aS10ZW1wb3JhbCBMYW5kc2F0IGltYWdlcnkuIFJlZCBhcmVhcyByZXByZXNlbnQgbmV3bHkgcmVjbGFpbWVkIGxhbmQgYmV0d2VlbiAyMDEw4oCTMjAyNSwgeWVsbG93IGJldHdlZW4gMjAwMOKAkzIwMTAsIGFuZCB3aGl0ZSBkZW5vdGVzIHN0YWJsZSBsYW5kIHByZXNlbnQgYWNyb3NzIGFsbCB0aHJlZSBwZXJpb2QuDQoNCmBgYHtyLCBmYWxzZSBjb2xvciBpbWFnZSAwMC0xMC0yNX0NCiAjIOWPluW+lyByYXN0ZXIg55qE5bqn5qiZ56+E5ZyNDQplIDwtIHRlcnJhOjpleHQobGFuZF9zdGFjaykNCg0KIA0KICMg6Kit5a6aIGxlZ2VuZCDkvY3nva7vvIjlj7PkuIvop5LlhafnuK4gNSXvvIkNCiB4X2xlZyA8LSBlJHhtYXggLSAwLjUgKiAoZSR4bWF4IC0gZSR4bWluKQ0KIHlfbGVnIDwtIGUkeW1heCAtIDAuMSAqIChlJHltYXggLSBlJHltaW4pICAjIHltaW4g5piv5LiL6Z2iIOKGkiDlvoDkuIogMjAlDQogDQogIyBwbG90DQogcGxvdFJHQigNCiAgIGxhbmRfc3RhY2ssIHIgPSA4LCBnID0gNSwgYiA9IDMsIHN0cmV0Y2ggPSAibGluIiwNCiAgbWFpbiA9ICJNYWNhdSBMYW5kIEV4cGFuc2lvbiAoMjAwMOKAkzIwMTDigJMyMDI1KSIpDQoNCm10ZXh0KA0KICAiRmFsc2UtY29sb3IgUmVwcmVzZW50YXRpb25cbm9mIE1hY2F1IExhbmQgRXhwYW5zaW9uXG4yMDAwIOKAoiAyMDEwIOKAoiAyMDI1IiwNCiAgIHNpZGUgPSAxLCAgICAgICAjIHRvcA0KICAgbGluZSA9IDIsICAgICAjIG1vdmUgY2xvc2VyIHRvIHBsb3QgKC0gbW92ZXMgaW5zaWRlKQ0KICAgYWRqID0gMC42LA0KICAgY2V4ID0gMS41LA0KICBmb250ID0gMSwNCiAgIGNvbCA9ICJ3aGl0ZSIgKQ0KIA0KIA0KICMgQ2FwdGlvbg0KIG10ZXh0KA0KICAiQ3JlYXRlZCBieSBKaWF0b25nIFN1IiwNCiAgc2lkZSA9IDEsDQogIGxpbmUgPSA0LA0KICBhZGogPSAwLjYyLA0KICBjZXggPSAxLA0KICBjb2wgPSAiZ3JleSIpDQogDQpsZWdlbmQoDQogICB4ID0geF9sZWcsDQogICB5ID0geV9sZWcsDQogICBsZWdlbmQgPSBjKA0KICAgICAiQ2hhbmdlIGJldHdlZW4gMjAxMC0yMDI1IiwNCiAgICAgIkNoYW5nZSBiZXR3ZWVuIDIwMDAtMjAxMCIsDQogICAgICJMYW5kIGluIGFsbCAzIHBlcmlvZHMiDQogICAgICMiV2F0ZXIiDQogICApLA0KICAgZmlsbCA9IGMoDQogICAgIHJnYigxLDAsMCksICAgIyByZWQgZm9yIDIwMjUNCiAgICAgcmdiKDEsMSwwKSwgICAjIHllbGxvdyBmb3IgMjAwMC0yMDEwDQogICAgIHJnYigxLDEsMSkgICAjIHdoaXRlIGluIGFsbCBwZXJpb2QNCiAgICAjcmdiKDAsMCwwKSAgICAjIGJsYWNrIGlzIHdhdGVyIA0KICAgKSwNCiAgIGJvcmRlciA9IE5BLA0KICAgY2V4ID0gMC44NSwNCiAgIGJnID0gTkEsDQogICB0ZXh0LmNvbCA9ICJ3aGl0ZSIsDQogICBidHkgPSAibiIgICApDQoNCmBgYA0KDQojIEludGVyYWN0aXZlIG1hcCANCg0KYGBge3J9DQoNCiNvbmx5IG9uZSBjb2xvciByZXByZXNlbnQgbGFuZO+8jHdhdGVyIGlzIE5BDQpwYWxfbGFuZCA8LSBjb2xvckZhY3RvcigNCiAgcGFsZXR0ZSA9IGMoIm9yYW5nZSIpLCAgIA0KICBkb21haW4gID0gYygxKSwNCiAgbmEuY29sb3IgPSAidHJhbnNwYXJlbnQiDQopDQoNCg0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQp5ZWFycyA8LSBjKCIxOTkwIiwiMTk5NSIsIjIwMDAiLCIyMDA1IiwiMjAxMCIsIjIwMTUiLCIyMDIwIiwiMjAyNSIpDQpsYXllcl9uYW1lcyA8LSBuYW1lcyhsYW5kX3N0YWNrKSAgIyAibGFuZF8xOTkwIiAuLi4NCg0KbSA8LSBsZWFmbGV0KCkgfD4NCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgICMgYmFzZW1hcA0KDQojIGFkZCBsYW5kIG1hc2sgZm9yIGVhY2ggeWVhcg0KZm9yIChpIGluIHNlcV9hbG9uZyhsYXllcl9uYW1lcykpIHsNCiAgbSA8LSBtIHw+DQogICAgYWRkUmFzdGVySW1hZ2UoDQogICAgICBsYW5kX3N0YWNrW1tpXV0sDQogICAgICBjb2xvcnMgID0gcGFsX2xhbmQsDQogICAgICBvcGFjaXR5ID0gMC44LA0KICAgICAgcHJvamVjdCA9IFRSVUUsICAgICAgICAgICAgICAgICAgIyAgV0dTODQgLSBsZWFmbGV0DQogICAgICBncm91cCAgID0geWVhcnNbaV0NCiAgICApDQp9DQoNCiMgbGF5ZXIgY29udHJvbChjaG9zZSB5ZWFyKQ0KbSA8LSBtIHw+DQogIGFkZExheWVyc0NvbnRyb2woDQogICAgb3ZlcmxheUdyb3VwcyA9IHllYXJzLA0KICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBGQUxTRSkNCiAgKSB8Pg0KICBhZGRDb250cm9sKA0KICAgICJORFdJLWJhc2VkIExhbmQgTWFzayBmb3IgTWFjYXUgKDE5OTDigJMyMDI1KSIsDQogICAgcG9zaXRpb24gPSAiYm90dG9tbGVmdCINCiAgKQ0KDQptICANCg0KYGBgDQoNCmBgYHtyIHNhdmUgaHRtbCwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoaHRtbHdpZGdldHMpDQoNCnNhdmVXaWRnZXQobSwgIm1hY2F1X3JlY2xhbWF0aW9uX2ludGVyYWN0aXZlLmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSkNCg0KYGBgDQoNCg==